import { _decorator, Asset, AssetManager, assetManager, AudioClip, Component, Node, Prefab, SpriteAtlas, SpriteFrame } from 'cc';
const { ccclass, property } = _decorator;

@ccclass('ResMgr')
export class ResMgr extends Component {
    /**
     * 单例
     */
    public static Instance: ResMgr = null;
    /**
     * 预加载资源数目
     */
    private total:number = 0;
    /**
     * 当前预加载资源数目
     */
    private now:number = 0;

    /**
     * 预加载 ab 包的数目
     */
    private totalAb:number = 0;

    /**
     * 已经加载 ab 包的数目
     */
    private nowAb:number = 0;
    
    /**
     * 
     */
    private progressFunc:Function = null;
    /**
     * 
     */
    private endFunc:Function = null;

    private abBunds:any = {};

    onLoad() {
        if(null === ResMgr.Instance) {
            ResMgr.Instance = this;
        }else{
            this.destroy();
            return;
        }
    }

    /**
     * 加载 ab 包
     * @param abName 资源包名
     * @param endFunc 回执函数
     */
    public loadAssetBundle(abName:string, endFunc:Function):void {     
        assetManager.loadBundle(abName, (err, ab) => {
            if(null !== err) {
                console.log("[ResMgr] loadAssetBundle err:", err);
                this.abBunds[abName] = null;
            }else{
                console.log("[ResMgr] loadAssetBundle success:", abName);
                this.abBunds[abName] = ab;
            }
            if(endFunc) endFunc();
        });
    }

    /**
     * 加载 bundle
     * @param bundle 资源包
     * @param url 
     * @param type 
     * @param endFunc 
     */
    private loadRes(bundle:AssetManager.Bundle, assetPath:string, typeClass:any, endFunc:Function):void { 
        if(null == bundle){
            if(endFunc) endFunc(null, null);
            return;
        }
        //
        bundle.load(assetPath, typeClass, (error, asset)=>{
            if(null != endFunc) endFunc(error, asset);
        });
    }

    /**
     * 
     * @param bundle 资源包
     * @param url 
     * @param typeClass 
     * @param endFunc 
     */
    private loadAssetRes(bundle:AssetManager.Bundle, url:string, typeClass:any):void {
        this.loadRes(bundle, url, typeClass, (error, asset)=>{
            this.now++;
            if(error){
                console.error("[ResMgr] loadAssetRes err:" + error + " url:" + url);
            }
            //
            if(this.progressFunc) this.progressFunc(this.now, this.total);
            //
            if(this.now >= this.total){
                if(this.endFunc) this.endFunc();
            }
        });
    }

    /**
     * 加载 ab 包中的资源
     * @param resPkg 资源包
     */
    private loadAssetsInAssetsBundle(resPkg:object):void{
        for(var key in resPkg){
            var urlSet = resPkg[key].urls;
            var typeClass:Asset = resPkg[key].assetType;
            //
            for(var i = 0; i < urlSet.length; i++){
                this.loadAssetRes(this.abBunds[key], urlSet[i], typeClass);
            }
        }
    }

    /**
     * ResPkg
     * @param resPkg resPkg = { ab包名字 : {assetType: cc.Prefab, urls:["路径1"]}}
     * @param progressFunc 
     * @param endFunc 
     */
    public preloadResPkg(resPkg:object, progressFunc:Function, endFunc:Function):void {
        // step1: 加载我们的 ab 包进来
        this.total = 0;
        this.now = 0;
        //
        this.totalAb = 0;
        this.nowAb = 0;
        //
        this.progressFunc = progressFunc;
        this.endFunc = endFunc;
        //
        for(var key in resPkg){
            this.totalAb++;//
            this.total += resPkg[key].urls.length;//总资源要加载的数目
        }
        //
        for(var key in resPkg){
            this.loadAssetBundle(key, ()=>{
                this.nowAb++;
                if(this.nowAb >= this.totalAb){
                    this.loadAssetsInAssetsBundle(resPkg);
                }
            });
        }

        // step2: 根据我们单个 ab 包的每个url,我们一个一个的资源加载进来
    }

    /**
     * 加载资源
     * @param abName 资源包名
     * @param resUrl 
     * @returns 
     */
    public getAsset(abName:string, resUrl:string):Asset{
        var bundle = this.abBunds[abName];
        if(null == bundle){
            console.log("[ResMgr] getAsset err:", abName, resUrl);
            return null;
        }
        //
        return bundle.get(resUrl);
    }

    /**
     * 获取AB包
     * @param abName 资源包名
     * @returns 
     */
    public getBundle(abName:string):AssetManager.Bundle{
        return this.abBunds[abName];
    }

    /**
     * 加载Prefab
     * @param abName 
     * @param url 
     * @param endFunc 
     * @returns 
     */
    public loadResByPrefab(abName:string, url:string, endFunc:Function):void { 
        var bundle = this.abBunds[abName];
        if(null == bundle){
            if(null != endFunc) endFunc(null);
            return;
        }
        //
        this.loadRes(bundle, url, Prefab, (error, asset)=>{
            if(null != asset && null != endFunc) endFunc(error, asset);
        });
    }

    /**
     * 加载 AudioClip
     * @param abName 资源包名
     * @param url 
     * @param endFunc 
     * @returns 
     */
    public loadResByAudioClip(abName:string, url:string, endFunc:Function):void {
        var bundle = this.abBunds[abName];
        if(null == bundle){
            if(null != endFunc) endFunc(null);
            return;
        }
        //
        this.loadRes(bundle, url, AudioClip, (error, asset)=>{
            if(null != asset && null != endFunc) endFunc(error, asset);
        });
    }

    /**
     * 加载 SpriteAtlas
     * @param abName 资源包名
     * @param url 
     * @param endFunc 
     * @returns 
     */
    public loadResBySpriteAtlas(abName:string, assetPath:string, endFunc:Function):void {
        var bundle = this.abBunds[abName];
        if(null == bundle){
            if(null != endFunc) endFunc(null);
            return;
        }
        //
        this.loadRes(bundle, assetPath, SpriteAtlas, (error, asset)=>{
            if(null != asset){
                if(null != endFunc) endFunc(asset);
            }else{
                if(null != error) console.error("[ResMgr] loadResBySpriteAtlas abName:" + abName + " ,assetPath:" + assetPath + " ,error:" + error)
                if(null != endFunc) endFunc(null);
            }
        })
    }
    /** 
     * 加载 SpriteFrame
     * @param abName 
     * @param spriteFramePath 
     * @param endFunc 
     * @returns 
     */
    public loadResBySpriteFrame(abName:string, spriteFramePath:string, endFunc:Function):void {
        var bundle:AssetManager.Bundle = this.abBunds[abName];
        if(null == bundle){
            if(null != endFunc) endFunc(null);
            return;
        }
        //
        bundle.loadDir(spriteFramePath, SpriteFrame, (error, asset)=>{
            if(!error){
                if(null != endFunc) endFunc(asset);
            }else{
                if(null != endFunc) endFunc(null);
            }
        })
    }

    /**
     * 加载 Asset
     * @param abName 资源包名
     * @param url 
     * @param endFunc 
     * @returns 
     */
    public loadResByAsset(abName:string, assetPath:string, endFunc:Function):void {
        var bundle = this.abBunds[abName];
        if(null == bundle){
            if(null != endFunc) endFunc(null);
            return;
        }
        //
        this.loadRes(bundle, assetPath, Asset, (error, asset)=>{
            if(null != asset){
                if(null != endFunc) endFunc(asset);
            }else{
                if(null != error) console.error("[ResMgr] loadResByAsset abName:" + abName + " ,assetPath:" + assetPath + " ,error:" + error)
                if(null != endFunc) endFunc(null);
            }
        })
    }
}

